#include <utility>

#include "bw_Upgrade.h"
#include "bw_errno.h"
#include "bw_xml.h"
#include "bw_FcgiRequest.h"
#include "bw_json_tool.h"
#include "bw_Str.h"
#include "bw_public.h"
//#include "common.h"
#include "MsgList.h"
#include "bw_file_tool.h"

#include <string>

namespace bwcgi
{
    const char* getFileInfo()
    {
        Enc_Upgrade * pFileInfoTask = new Enc_Upgrade();
        eENC_ERROR code = pFileInfoTask->getFileCfg();
        delete pFileInfoTask;
        pFileInfoTask = nullptr;
        if(code != BWENC_ERROR_NONE)
            return  bwenc_common_ack(code);
        return Enc_Upgrade::respStr.c_str();
    }

    const char* getEncryptPkg(FcgiRequest* pFcgiReq)
    {
        Enc_Upgrade * pEncryPkgTask = new Enc_Upgrade();
        eENC_ERROR code = pEncryPkgTask->opensslUpgPkg(pFcgiReq);
        delete pEncryPkgTask;
        pEncryPkgTask = nullptr;
        if(FCGI_file_exist(pFcgiReq->getUploadfile()))
        {
            char cmd[CMD_LEN] = {0};
            snprintf(cmd, CMD_LEN, "rm %s -f", pFcgiReq->getUploadfile());
            cgi_debug("rm_cmd = %s", cmd);
            system(cmd);
            sync();
        }
        return bwenc_common_ack(code);
    }

    const char* getFileMd5(FcgiRequest *pFcgiReq)
    {
        Enc_Upgrade * pFileMd5Task = new Enc_Upgrade();
        pFileMd5Task->getSigMd5Value(pFcgiReq);
        delete pFileMd5Task;
        pFileMd5Task = nullptr;
        if(Enc_Upgrade::respStr.empty())
            return bwenc_common_ack(BW_ERROR_GET_FILEMD5);

        return Enc_Upgrade::respStr.c_str();
    }
    string Enc_Upgrade::processStr;
    string Enc_Upgrade::respStr;
    BW_JSONCFG Enc_Upgrade::jsoncfg = {false, "", "", ""};

    const map<string, PROCESS_REPLY> Enc_Upgrade::proMsg = {
            {"START_UPGRADE_ERROR", {"开启升级程序失败", "ERROR"}},
            {"UPGRADE_ALREADY_RUN", {"升级还在进行，请稍后再试", "ERROR"}},
            {"JSON_CFG_ERROR", {"配置文件读取失败", "ERROR"}},
            {"READ_PIPE_ERROR", {"读取升级信息失败", "ERROR"}},
            {"JSON_CFG_ERROR", {"管道信息错误", "ERROR"}},

            {"UPG_ERROR_LOCAL_PARAM", {"本地升级传参不合法", "ERROR"}},
            {"UPG_ERROR_LOCALCFG_INVALID", {"本地配置文件不合法", "ERROR"}},
            {"UPG_ERROR_UNENCRYPT", {"解密失败", "ERROR"}},
            {"UPG_ERROR_UNZIP", {"解压失败", "ERROR"}},
            {"UPG_ERROR_PARSE_UPGCFG", {"升级配置文件解析错误", "ERROR"}},
            {"UPG_ERROR_UPGCFG_INVAILD", {"升级配置文件不合法", "ERROR"}},
            {"UPG_ERROR_BAKFILE", {"备份文件完成", "ERROR"}},
            {"UPG_ERROR_UPGRADE", {"升级文件出错", "ERROR"}},
            {"UPG_ERROR_RECOVER", {"还原失败", "RECOVER_ERROR"}},

            {"START_UPGRADE_SUCCESS", {"开启升级程序成功", "5"}},
            {"UPG_SUCCESS_LOCAL_PARAM", {"获取本地配置成功", "10"}},
            {"UPG_SUCCESS_LOCALCFG_CHECK", {"校验本地配置成功", "20"}},
            {"UPG_SUCCESS_UNENCRYPT", {"解密成功", "25"}},
            {"UPG_SUCCESS_UNZIP", {"解压成功", "30"}},
            {"UPG_SUCCESS_PARSE_UPGCFG", {"升级配置文件解析完成", "40"}},
            {"UPG_SUCCESS_UPGCFG_CHECK", {"升级配置文件校验完成", "50"}},
            {"UPG_SUCCESS_BAKFILE", {"备份文件完成", "85"}},
            {"UPG_SUCCESS_UPGRADE", {"升级文件完成", "95"}},
            {"UPG_SUCCESS_REMOTE_RECOVER", {"远端复原成功", "RECOVER SUCCESS"}},
            {"UPG_SUCCESS_RECOVER", {"还原完成", "RECOVER_SUCCESS"}},

            {"UPG_ERROR_REMOTE_TCP_CHECK", {"远端TCP连接失败", "ERROR"}},
            {"UPG_SUCCESS_REMOTE_TCP_CHECK", {"远端TCP连接成功", "45"}},
            {"UPG_ERROR_REMOTE_UPGCFG", {"远端升级配置文件校验失败", "ERROR"}},
            {"UPG_SUCCESS_REMOTE_UPGCFG", {"远端升级配置文件校验完成", "65"}},
            {"UPG_ERROR_REMOTE_UPGRADE", {"远端升级失败", "ERROR"}},
            {"UPG_SUCCESS_REMOTE_UPGRADE", {"远端升级成功", "75"}},
            {"UPG_ALL_SWITCH_OFF", {"升级开关全部关闭", "ERROR"}},

            {"UPGRADE_FINISH", {"升级结束", "100"}},
    };

    bool Enc_Upgrade::initJsonCfg()
    {
        FILE * fp = fopen(JSONCFG_LOCATION, "r");
        if(nullptr == fp)
        {
            cgi_debug("JSONCFG NAME ERROR, FOPEN ERROR : %s", JSONCFG_LOCATION);
            return false;
        }
        int fileSize = FCGI_file_size(JSONCFG_LOCATION);
        char * buf = new char[fileSize+1];
        memset(buf, 0, fileSize+1);
        fread(buf, 1, fileSize, fp);
        buf[fileSize] = '\0';
        fclose(fp);
        cgi_debug("PARSE JSON : \n%s", buf);
        rapidjson::Document m_doc;
        m_doc.Parse(buf);
        delete []buf;
        buf = nullptr;
        if(m_doc.HasParseError() || !m_doc.IsObject())
        {
            cgi_debug("PARSE JSON FILE ERROR");
            return false;
        }
        rapidjson::StringBuffer sb;
        rapidjson::PrettyWriter<rapidjson::StringBuffer> ptWriter(sb);
        m_doc.Accept(ptWriter);
//        cgi_debug("json cfg : \n%s", sb.GetString());
        RAPIDJSON_GET_STR_VAL(m_doc, PIPENAME_KEY, jsoncfg.pipeName, "");
        RAPIDJSON_GET_STR_VAL(m_doc, XMLCFGNAME_KEY, jsoncfg.xmlCfgName, "");
        RAPIDJSON_GET_STR_VAL(m_doc, UPGRADESERVER_KEY, jsoncfg.upgradeServer, "");
        if(jsoncfg.pipeName.empty() || jsoncfg.xmlCfgName.empty() || jsoncfg.upgradeServer.empty())
        {
            cgi_debug("GET ATTR ERROR");
            return false;
        }

        if(!m_doc.HasMember(MSGLIST_KEY) || !m_doc[MSGLIST_KEY].IsObject())
        {
            cgi_debug("%s ERROR", MSGLIST_KEY);
            return false;
        }
        rapidjson::Value & msgList = m_doc[MSGLIST_KEY];
        RAPIDJSON_GET_STR_VAL(msgList, MSGPATH_KEY, jsoncfg.msgPath, "");
        RAPIDJSON_GET_INT_VAL(msgList, PROJECTID_KEY, jsoncfg.projectId, 0);
        RAPIDJSON_GET_INT_VAL(msgList, MSGTYPE_KEY, jsoncfg.msgType, 0);
        if(jsoncfg.msgPath.empty() || jsoncfg.projectId == 0 || jsoncfg.msgType == 0)
        {
            cgi_debug("GET %s ATTR ERROR", MSGLIST_KEY);
            return false;
        }
        jsoncfg.isInit = true;

        return true;
    }

    Enc_Upgrade::Enc_Upgrade()
    {
        InitData();
    }

    Enc_Upgrade::~Enc_Upgrade()
    {

    }

    void Enc_Upgrade::InitData()
    {
        respStr.clear();
        upgXmlName.clear();
        pkgName.clear();
        pkgMd5Value.clear();
        upgXmlStr.clear();

        local_data.isInit = false;
        local_data.execFileInfo.clear();
        local_data.normFileInfo.clear();
        local_data.execNum = 0xFFFF;
        local_data.normNum = 0xFFFF;

        upg_data.isInit = false;
        upg_data.execFileInfo.clear();
        upg_data.normFileInfo.clear();
        upg_data.execNum = 0XFFFF;
        upg_data.normNum = 0XFFFF;
    }
    bool Enc_Upgrade::getLocalXml()
    {
        TiXmlDocument * doc = new TiXmlDocument(jsoncfg.xmlCfgName.c_str());
//        cgi_debug("xmlName = %s", jsoncfg.xmlCfgName.c_str());
        doc->LoadFile();
        if(doc->Error())
        {
            cgi_debug("XML CONTENT INVALID :%s", jsoncfg.xmlCfgName.c_str());;
            delete doc;
            return false;
        }
        TiXmlElement * root = doc->FirstChildElement();
        if(nullptr == root)
        {
            cgi_debug("XML ROOT ERROR");
            delete doc;
            return false;
        }

        TiXmlElement * execFile = root->FirstChildElement(EXECFILE_KEY);
        if (nullptr == execFile)
        {
            cgi_debug("GET EXECFILE ERROR");
            delete doc;
            return false;
        }

        TiXmlElement * cfg = execFile->FirstChildElement(CFG_KEY);
        for(; cfg != nullptr; cfg = cfg->NextSiblingElement())
        {
            EXEC_FILE sigFileInfo;
            TINY_XML_GET_INT_ATTR(cfg, INDEX_KEY, sigFileInfo.index, 0xffff);
            TINY_XML_GET_INT_ATTR(cfg, UPG_SWITCH_KEY, sigFileInfo.upgSwitch, 0xff);
            TINY_XML_GET_STR_ATTR(cfg, FILENAME_KEY, sigFileInfo.fileName, "");
            TINY_XML_GET_STR_ATTR(cfg, FILEPATH_KEY, sigFileInfo.filePath, "");
            TINY_XML_GET_STR_ATTR(cfg, VERSION_KEY, sigFileInfo.version, "");
            TINY_XML_GET_STR_ATTR(cfg, MD5_KEY, sigFileInfo.md5Value, "");
            TINY_XML_GET_INT_ATTR(cfg, ISREMOTE_KEY, sigFileInfo.isRemote, 0xff);
            TINY_XML_GET_INT_ATTR(cfg, ISPROTECT_KEY, sigFileInfo.isProtected, 0xff);
            TINY_XML_GET_INT_ATTR(cfg, ISADDITION_KEY, sigFileInfo.isAddition, 0xff);
            TINY_XML_GET_STR_ATTR(cfg, PARAM_KEY, sigFileInfo.param, "");
            if((sigFileInfo.index >= 0xffff) || (sigFileInfo.upgSwitch >= 0xff) || (sigFileInfo.isRemote >= 0xff)
                || (sigFileInfo.isProtected >= 0xff) || (sigFileInfo.isAddition >= 0xff) || (sigFileInfo.fileName.empty())
                || (sigFileInfo.filePath.empty()) || (sigFileInfo.md5Value.empty()) || (sigFileInfo.version.empty()))
            {
                cgi_debug("GET SIG EXECFILE ERROR");
                delete doc;
                return false;
            }
            local_data.execFileInfo.push_back(move(sigFileInfo));
        }
        TINY_XML_GET_INT_ATTR(execFile, CFG_NUMBER_KEY, local_data.execNum, 0xffff);
        if(local_data.execNum != (int)local_data.execFileInfo.size())
        {
            cgi_debug("EXECFILE NUM PARSE ERROR : %d, %d", local_data.execNum, local_data.execFileInfo.size());
            delete doc;
            return false;
        }

        TiXmlElement * normFile = execFile->NextSiblingElement(NORMALFILE_KEY);
        if(nullptr == normFile)
        {
            cgi_debug("GET NORMFILE ERROR");
            delete doc;
            return  false;
        }
        cfg = normFile->FirstChildElement(CFG_KEY);
        for(; cfg != nullptr; cfg = cfg->NextSiblingElement())
        {
            NORM_FILE sigFileInfo;
            TINY_XML_GET_INT_ATTR(cfg, INDEX_KEY, sigFileInfo.index, 0xffff);
            TINY_XML_GET_INT_ATTR(cfg, UPG_SWITCH_KEY, sigFileInfo.upgSwitch, 0xff);
            TINY_XML_GET_STR_ATTR(cfg, FILENAME_KEY, sigFileInfo.fileName, "");
            TINY_XML_GET_STR_ATTR(cfg, FILEPATH_KEY, sigFileInfo.filePath, "");
            TINY_XML_GET_STR_ATTR(cfg, VERSION_KEY, sigFileInfo.version, "");
            TINY_XML_GET_STR_ATTR(cfg, VERSIONFILE_KEY, sigFileInfo.versionFileName, "");
            TINY_XML_GET_STR_ATTR(cfg, MD5_KEY, sigFileInfo.md5Value, "");
            TINY_XML_GET_INT_ATTR(cfg, ISREMOTE_KEY, sigFileInfo.isRemote, 0xff);
            TINY_XML_GET_INT_ATTR(cfg, ISADDITION_KEY, sigFileInfo.isAddition, 0xff);
            if((sigFileInfo.index >= 0xffff) || (sigFileInfo.upgSwitch >= 0xff) || (sigFileInfo.isRemote >= 0xff)
               || (sigFileInfo.isAddition >= 0xff) || (sigFileInfo.fileName.empty()) || (sigFileInfo.versionFileName.empty())
               || (sigFileInfo.filePath.empty()) || (sigFileInfo.md5Value.empty()) || (sigFileInfo.version.empty()))
            {
                cgi_debug("GET SIG NORM ERROR");
                delete doc;
                return false;
            }
            local_data.normFileInfo.push_back(move(sigFileInfo));
        }
        TINY_XML_GET_INT_ATTR(normFile, CFG_NUMBER_KEY, local_data.normNum, 0xffff);
        if(local_data.normNum != (int)local_data.normFileInfo.size())
        {
            cgi_debug("NORM NUM PARSE ERROR");
            delete doc;
            return false;
        }

        local_data.isInit = true;
        delete doc;
        return true;
    }

    bool Enc_Upgrade::buildLocalJson()
    {
        if(!local_data.isInit)
        {
            cgi_debug("LOCAL XML GET ERROR");
            return false;
        }
        rapidjson::Document doc;
        doc.SetObject();
        rapidjson::Document::AllocatorType & allocator = doc.GetAllocator();
        doc.AddMember(RETCOD_KEY, 0, allocator);
        doc.AddMember(RETMSG_KEY, rapidjson::StringRef(SUCCESS_KEY), allocator);

        rapidjson::Value retData(rapidjson::kObjectType);
        retData.AddMember(EXECNUM_KEY, local_data.execNum, allocator);
        retData.AddMember(NORMNUM_KEY, local_data.normNum, allocator);

        rapidjson::Value execFileArray(rapidjson::kArrayType);
        rapidjson::Value normFileArray(rapidjson::kArrayType);
        for(auto & i : local_data.execFileInfo)
        {
            rapidjson::Value sigExeFile(rapidjson::kObjectType);
            sigExeFile.AddMember(INDEX_KEY, i.index, allocator);
            sigExeFile.AddMember(FILENAME_KEY, rapidjson::StringRef(i.fileName.c_str()), allocator);
            sigExeFile.AddMember(FILEPATH_KEY, rapidjson::StringRef(i.filePath.c_str()), allocator);
            sigExeFile.AddMember(VERSION_KEY, rapidjson::StringRef(i.version.c_str()), allocator);
            sigExeFile.AddMember(MD5_KEY, rapidjson::StringRef(i.md5Value.c_str()), allocator);
            sigExeFile.AddMember(PARAM_KEY, rapidjson::StringRef(i.param.c_str()), allocator);
            sigExeFile.AddMember(SWITCH_KEY, i.upgSwitch, allocator);
            sigExeFile.AddMember(ISREMOTE_KEY, i.isRemote, allocator);
            sigExeFile.AddMember(ISPROTECT_KEY, i.isProtected, allocator);
            sigExeFile.AddMember(ISADDITION_KEY, 0, allocator);
            execFileArray.PushBack(sigExeFile, allocator);
        }

        for(auto & i : local_data.normFileInfo)
        {
            rapidjson::Value sigNormFile(rapidjson::kObjectType);
            sigNormFile.AddMember(INDEX_KEY, i.index, allocator);
            sigNormFile.AddMember(FILENAME_KEY, rapidjson::StringRef(i.fileName.c_str()), allocator);
            sigNormFile.AddMember(FILEPATH_KEY, rapidjson::StringRef(i.filePath.c_str()), allocator);
            sigNormFile.AddMember(VERSION_KEY, rapidjson::StringRef(i.version.c_str()), allocator);
            sigNormFile.AddMember(VERSIONFILE_KEY, rapidjson::StringRef(i.versionFileName.c_str()), allocator);
            sigNormFile.AddMember(MD5_KEY, rapidjson::StringRef(i.md5Value.c_str()), allocator);
            sigNormFile.AddMember(SWITCH_KEY, i.upgSwitch, allocator);
            sigNormFile.AddMember(ISREMOTE_KEY, i.isRemote, allocator);
            sigNormFile.AddMember(ISADDITION_KEY, 0, allocator);
            normFileArray.PushBack(sigNormFile, allocator);
        }
        retData.AddMember(EXECFILE_KEY, execFileArray, allocator);
        retData.AddMember(NORMALFILE_KEY, normFileArray, allocator);
        doc.AddMember(RETDATA_KEY, retData, allocator);

        rapidjson::StringBuffer sb;
        rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
        doc.Accept(writer);

        respStr = sb.GetString();
//        cgi_debug("build json:\n%s", respStr.c_str());
        return true;
    }

    eENC_ERROR Enc_Upgrade::getFileCfg()
    {
        bool ret;
        if(!jsoncfg.isInit)
            initJsonCfg();
        ret = getLocalXml();
        if(!ret)
        {
            cgi_debug("GET XML INFO ERROR");
            return BW_ERROR_GET_FILEINFO;
        }

        ret = buildLocalJson();
        if(!ret || respStr.empty())
        {
            cgi_debug("GET XML INFO ERROR");
            return BW_ERROR_GET_FILEINFO;
        }

        return BWENC_ERROR_NONE;
    }

    bool Enc_Upgrade::getUpgJson(const char* json)
    {
        if(nullptr == json)
        {
            cgi_debug("PARAM INVAILID");
            return false;
        }

        rapidjson::Document doc;
        doc.Parse(json);
        if(doc.HasParseError() || !doc.IsObject())
        {
            cgi_debug("JSON PARSE ERROR");
            return false;
        }

        string tmpStr;
        RAPIDJSON_GET_STR_VAL(doc, MODULE_KEY, tmpStr, "");
        if((UPGRADE_KEY != tmpStr) || (tmpStr.empty()))
        {
            cgi_debug("JSON INVALID");
            return false;
        }
        RAPIDJSON_GET_STR_VAL(doc, REQUEST_KEY, tmpStr, "");
        if((SET_UPGCFG_KEY != tmpStr) || (tmpStr.empty()))
        {
            cgi_debug("JSON INVALID");
            return false;
        }

        if(!doc.HasMember(PARAM_KEY) || (!doc[PARAM_KEY].IsObject()))
        {
            cgi_debug("JSON INVALID");
            return false;
        }
        rapidjson::Value & param = doc[PARAM_KEY];
        RAPIDJSON_GET_STR_VAL(param, PKGNAME_KEY, tmpStr, "");
        if(tmpStr.size() < 5 || (".zip" != tmpStr.substr(tmpStr.size() - 4)))
        {
            cgi_debug("JSON INVALID : %s", tmpStr.c_str());
            return false;
        }
        pkgName = tmpStr;
        RAPIDJSON_GET_STR_VAL(param, MD5_KEY, tmpStr, "");
        if(tmpStr.empty())
        {
            cgi_debug("JSON INVALID");
            return false;
        }
        pkgMd5Value = move(tmpStr);

        if(!param.HasMember(EXECFILE_KEY) || !param[EXECFILE_KEY].IsArray())
        {
            cgi_debug("JSON INVALID");
            return false;
        }
        rapidjson::Value & execFileArray = param[EXECFILE_KEY];
        for(U32 i = 0; i < execFileArray.Size(); i++)
        {
            EXEC_FILE sigFile;
            RAPIDJSON_GET_INT_VAL(execFileArray[i], INDEX_KEY, sigFile.index, 0XFFFF);
            RAPIDJSON_GET_STR_VAL(execFileArray[i], FILENAME_KEY, sigFile.fileName, "");
            RAPIDJSON_GET_STR_VAL(execFileArray[i], FILEPATH_KEY, sigFile.filePath, "");
            RAPIDJSON_GET_STR_VAL(execFileArray[i], MD5_KEY, sigFile.md5Value, "");
            RAPIDJSON_GET_STR_VAL(execFileArray[i], VERSION_KEY, sigFile.version, "");
            RAPIDJSON_GET_STR_VAL(execFileArray[i], PARAM_KEY, sigFile.param, "");
            RAPIDJSON_GET_INT_VAL(execFileArray[i], SWITCH_KEY, sigFile.upgSwitch, 0XFF);
            RAPIDJSON_GET_INT_VAL(execFileArray[i], ISADDITION_KEY, sigFile.isAddition, 0XFF);
            RAPIDJSON_GET_INT_VAL(execFileArray[i], ISPROTECT_KEY, sigFile.isProtected, 0XFF);
            RAPIDJSON_GET_INT_VAL(execFileArray[i], ISREMOTE_KEY, sigFile.isRemote, 0XFF);
            if(sigFile.fileName.empty() || sigFile.filePath.empty() || sigFile.version.empty()
              || sigFile.md5Value.empty() || sigFile.isRemote >= 0XFF || sigFile.upgSwitch >= 0XFF
              || sigFile.isProtected >= 0XFF || sigFile.isAddition >= 0XFF || sigFile.index >= 0XFFFF)
            {
                cgi_debug("JSON INVALID");
                return false;
            }
            upg_data.execFileInfo.push_back(move(sigFile));
        }
        if(upg_data.execFileInfo.size() != execFileArray.Size())
        {
            cgi_debug("JSON INVALID");
            return false;
        }
        upg_data.execNum = (int)upg_data.execFileInfo.size();

        rapidjson::Value & normFileArray = param[NORMALFILE_KEY];
        for(U32 i = 0; i < normFileArray.Size(); i++)
        {
            NORM_FILE sigFile;
            RAPIDJSON_GET_INT_VAL(normFileArray[i], INDEX_KEY, sigFile.index, 0XFFFF);
            RAPIDJSON_GET_STR_VAL(normFileArray[i], FILENAME_KEY, sigFile.fileName, "");
            RAPIDJSON_GET_STR_VAL(normFileArray[i], FILEPATH_KEY, sigFile.filePath, "");
            RAPIDJSON_GET_STR_VAL(normFileArray[i], MD5_KEY, sigFile.md5Value, "");
            RAPIDJSON_GET_STR_VAL(normFileArray[i], VERSION_KEY, sigFile.version, "");
            RAPIDJSON_GET_STR_VAL(normFileArray[i], VERSIONFILE_KEY, sigFile.versionFileName, "");
            RAPIDJSON_GET_INT_VAL(normFileArray[i], SWITCH_KEY, sigFile.upgSwitch, 0XFF);
            RAPIDJSON_GET_INT_VAL(normFileArray[i], ISADDITION_KEY, sigFile.isAddition, 0XFF);
            RAPIDJSON_GET_INT_VAL(normFileArray[i], ISREMOTE_KEY, sigFile.isRemote, 0XFF);
            if(sigFile.fileName.empty() || sigFile.filePath.empty() || sigFile.version.empty()
               || sigFile.versionFileName.empty() || sigFile.md5Value.empty() || sigFile.index >= 0XFFFF
               || sigFile.isRemote >= 0XFF || sigFile.upgSwitch >= 0XFF || sigFile.isAddition >= 0XFF)
            {
                cgi_debug("JSON INVALID");
                return false;
            }
            upg_data.normFileInfo.push_back(move(sigFile));
        }
        if(upg_data.normFileInfo.size() != normFileArray.Size())
        {
            cgi_debug("JSON INVALID");
            return false;
        }
        upg_data.normNum = (int)upg_data.normFileInfo.size();
        return true;
    }

    void Enc_Upgrade::buildUpgXml()
    {
        TiXmlDocument * doc = new TiXmlDocument;
        TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "UTF-8", "");
        doc->LinkEndChild(decl);
        TiXmlElement * root = new TiXmlElement(PRODUCT_KEY);
        root->SetAttribute(PRODUCT_KEY, ENCODER_KEY);
        root->SetAttribute(PKGNAME_KEY, pkgName.c_str());
        root->SetAttribute(MD5_KEY, pkgMd5Value.c_str());

        TiXmlElement * execfile = new TiXmlElement(EXECFILE_KEY);
        root->LinkEndChild(execfile);
        execfile->SetAttribute(CFG_NUMBER_KEY, upg_data.execNum);
        for(auto & i : upg_data.execFileInfo)
        {
            TiXmlElement * cfg = new TiXmlElement(CFG_KEY);
            execfile->LinkEndChild(cfg);
            cfg->SetAttribute(INDEX_KEY, i.index);
            cfg->SetAttribute(UPG_SWITCH_KEY, i.upgSwitch);
            cfg->SetAttribute(FILENAME_KEY, i.fileName.c_str());
            cfg->SetAttribute(FILEPATH_KEY, i.filePath.c_str());
            cfg->SetAttribute(VERSION_KEY, i.version.c_str());
            cfg->SetAttribute(PARAM_KEY, i.param.c_str());
            cfg->SetAttribute(ISREMOTE_KEY, i.isRemote);
            cfg->SetAttribute(ISADDITION_KEY, i.isAddition);
            cfg->SetAttribute(ISPROTECT_KEY, i.isProtected);
            cfg->SetAttribute(MD5_KEY, i.md5Value.c_str());
        }

        TiXmlElement * normFile = new TiXmlElement(NORMALFILE_KEY);
        root->LinkEndChild(normFile);
        normFile->SetAttribute(CFG_NUMBER_KEY, upg_data.normNum);
        for(auto & i : upg_data.normFileInfo)
        {
            TiXmlElement * cfg = new TiXmlElement(CFG_KEY);
            normFile->LinkEndChild(cfg);
            cfg->SetAttribute(INDEX_KEY, i.index);
            cfg->SetAttribute(UPG_SWITCH_KEY, i.upgSwitch);
            cfg->SetAttribute(FILENAME_KEY, i.fileName.c_str());
            cfg->SetAttribute(FILEPATH_KEY, i.filePath.c_str());
            cfg->SetAttribute(VERSION_KEY, i.version.c_str());
            cfg->SetAttribute(VERSIONFILE_KEY, i.versionFileName.c_str());
            cfg->SetAttribute(ISREMOTE_KEY, i.isRemote);
            cfg->SetAttribute(ISADDITION_KEY, i.isAddition);
            cfg->SetAttribute(MD5_KEY, i.md5Value.c_str());
        }
        doc->LinkEndChild(root);
        TiXmlPrinter *printer = new TiXmlPrinter();
        doc->Accept(printer);
        upgXmlStr = printer->CStr();

        delete printer;
        delete doc;
    }


    eENC_ERROR Enc_Upgrade::setUpgCfg(const char *json)
    {
        if(!jsoncfg.isInit)
            initJsonCfg();
        size_t fnPos = jsoncfg.xmlCfgName.rfind('/');
        if(string::npos != fnPos)
            upgXmlName = jsoncfg.xmlCfgName.substr(fnPos+1);
        if(upgXmlName.empty())
            return BW_ERROR_LOAD_JSONCFG;

        bool ret = getUpgJson(json);
        if(!ret)
        {
            cgi_debug("GET UPG JSON ERROR");
            return BW_ERROR_UPG_INFO;
        }
        buildUpgXml();
        cgi_debug("xml = \n%s", upgXmlStr.c_str());

        if(!Upg_File::checkAndCreatePath(TEMP_UPG_XML))
        {
            cgi_debug("checkAndCreatePath ERROR");
            return BW_ERROR_BUILD_UPGXML;
        }
        Upg_File::deleteAllFileInPath(TEMP_UPG_XML);

        char xmlName[1024] = {0};
        snprintf(xmlName, sizeof(xmlName), "%s%s", TEMP_UPG_XML, upgXmlName.c_str());
        cgi_debug("xmlName = %s", xmlName);
        FCGI_file_write(xmlName, upgXmlStr.c_str(), (int)upgXmlStr.size());
        if(upgXmlStr.size() != (U32)FCGI_file_size(xmlName))
        {
            cgi_debug("XML SIZE ERROR");
            return BW_ERROR_BUILD_UPGXML;
        }

        return BWENC_ERROR_NONE;
    }

    eENC_ERROR Enc_Upgrade::downloadUpgXml(FcgiRequest* pFcgiReq)
    {
        if(!jsoncfg.isInit)
            initJsonCfg();
        size_t fnPos = jsoncfg.xmlCfgName.rfind('/');
        if(string::npos != fnPos)
            upgXmlName = jsoncfg.xmlCfgName.substr(fnPos+1);
        if(upgXmlName.empty())
            return BW_ERROR_LOAD_JSONCFG;

        char xmlName[1024] = {0};
        snprintf(xmlName, sizeof(xmlName), "%s%s", TEMP_UPG_XML, upgXmlName.c_str());
        cgi_debug("xmlName = %s", xmlName);
        if(!FCGI_file_exist(xmlName) || FCGI_file_size(xmlName) <= 0)
        {
            cgi_debug("FILE NOT EXIST : %s", xmlName);
            return BW_ERROR_FILE_NOT_EXIST;
        }

        pFcgiReq->enableDown();
        pFcgiReq->setDownloadfile(xmlName);
        return BWENC_ERROR_NONE;
    }

    const char * Enc_Upgrade::beginUpgrade(const string &upgradeFileName)
    {
        processStr.clear();
        if(!jsoncfg.isInit)
            initJsonCfg();
        if(upgradeFileName.empty() || !FCGI_file_exist(upgradeFileName.c_str()))
        {
            cgi_debug("upgradeFileName ERROR : %s", upgradeFileName.c_str());
            return buildProcessJson("START_UPGRADE_ERROR");
        }
        if(jsoncfg.xmlCfgName.empty() || !FCGI_file_exist(jsoncfg.xmlCfgName.c_str()))
        {
            cgi_debug("xmlCfgName error :%s", jsoncfg.xmlCfgName.c_str());
            return buildProcessJson("START_UPGRADE_ERROR");
        }
        if(jsoncfg.upgradeServer.empty() || !FCGI_file_exist(jsoncfg.upgradeServer.c_str()))
        {
            cgi_debug("upgradeServer error :%s", jsoncfg.upgradeServer.c_str());
            return buildProcessJson("START_UPGRADE_ERROR");
        }
        if(Upg_File::progressIsRun(jsoncfg.upgradeServer.c_str()))
        {
            cgi_debug("%s still run", jsoncfg.upgradeServer.c_str());
            return buildProcessJson("UPGRADE_ALREADY_RUN");
        }

        /*  清空信号量和消息队列  */
        MsgList *pMsg = new MsgList(jsoncfg.msgPath.c_str(), jsoncfg.projectId);
        pMsg->deleteMsgList();
        SAFE_DELETE_PTR(pMsg);

        char cmd[1024] = {0};
        snprintf(cmd, sizeof(cmd), "%s -upgrade %s %s %s &", jsoncfg.upgradeServer.c_str(), upgradeFileName.c_str(), jsoncfg.xmlCfgName.c_str(), JSONCFG_LOCATION);
        cgi_debug("cmd = %s", cmd);
        system(cmd);
        sync();
        usleep(200000);
        if(!Upg_File::progressIsRun(jsoncfg.upgradeServer.c_str()))
        {
            cgi_debug("PROGRESS IS NOT RUN: %s", jsoncfg.upgradeServer.c_str());
            return buildProcessJson("START_UPGRADE_ERROR");
        }

        return buildProcessJson("START_UPGRADE_SUCCESS");
    }

    const char * Enc_Upgrade::getUpgProcess()
    {
        bool ret;
        if(!jsoncfg.isInit){
            ret = initJsonCfg();
            if (!ret)
            {
                cgi_debug("INIT JSONCFG ERROR");
                return buildProcessJson("JSON_CFG_ERROR");
            }
        }
        /* msgList */
        BWMsg msg;
        msg.type = jsoncfg.msgType;
        memset(msg.content, 0, sizeof(msg.content));
        MsgList * pGetMsg = new MsgList(jsoncfg.msgPath.c_str(), jsoncfg.projectId);
        pGetMsg->getMsg(&msg, sizeof(msg.content));
        string key = msg.content;
        SAFE_DELETE_PTR(pGetMsg);
        cgi_debug("key = %s",key.c_str());
        if(UPGRADE_FINISH_FALG == key) {
            Upg_File::stopProgress(jsoncfg.upgradeServer.c_str());
        }
        if(!key.empty()) {
            processStr.clear();
            processStr = buildProcessJson(key);
        }
        else if(processStr.empty())
            processStr = buildProcessJson("READ_PIPE_ERROR");

#if 0
        /*  PIPE  */
        int pipe_fd = open(jsoncfg.pipeName.c_str(), O_RDONLY | O_NONBLOCK);
        if (-1 == pipe_fd) {
            cgi_debug("open pipe error(pipeFile:%s)", jsoncfg.pipeName.c_str());
            usleep(300000);
        }
        if(-1 == pipe_fd)
        {
            cgi_debug("open pipe error");
            return processStr.empty() ? proMsg.find("READ_PIPE_ERROR")->second.c_str() : processStr.c_str();
        }
        usleep(100000);
        int trynum = 3;
        while(trynum--) {
            char content[1024] = {0};
            int res = read(pipe_fd, content, sizeof(content));
            if (-1 == res) {
                cgi_debug("read pipe error, try agian(%d)", 3-trynum);
                usleep(10000);
                continue;
            }
            close(pipe_fd);
            string key = content;
            cgi_debug("key = %s",key.c_str());
            if(!key.empty())
            {
                auto iterator = proMsg.find(key);
                if (iterator != proMsg.end())
                    processStr = iterator->second;
                else
                    processStr = proMsg.find("PIPE_INFO_INVALID")->second;
            }
            else if(processStr.empty())
                processStr = proMsg.find("READ_PIPE_ERROR")->second;
            break;
        }
#endif
        return processStr.c_str();
    }

    FILE_INFO Enc_Upgrade::getLocalFileInfo()
    {
        if(!jsoncfg.isInit)
            initJsonCfg();
        if(!local_data.isInit)
            getLocalXml();

        FILE_INFO temp(move(local_data));
            local_data.isInit = false;
        return move(temp);

    }

    eENC_ERROR Enc_Upgrade::opensslUpgPkg(FcgiRequest *pFcgiReq)
    {
        string passWord;
        if(pFcgiReq->getQuery(BW_KEY_PASSWORD))
            passWord = pFcgiReq->getQuery(BW_KEY_PASSWORD);
        if(passWord.empty()) {
            cgi_debug("PASSWORD INVALID");
            return BW_ERROR_PASSWORD_INVALID;
        }

        string pkgScr;
        if(pFcgiReq->getUploadfile())
            pkgScr = pFcgiReq->getUploadfile();
        if(pkgScr.size() < 5 || pFcgiReq->getUploadfileLen() == 0 ||
           ".zip" != pkgScr.substr(pkgScr.size()-4))
        {
            cgi_debug("PKG INVALID");
            return BW_ERROR_OPENSSL_PKG;
        }

        string pkgDst = TEMP_OPENSSL_PATH;
        bool ret = Upg_File::checkAndCreatePath(pkgDst.c_str());
        if(!ret)
        {
            cgi_debug("checkAndCreatePath error");
            return BW_ERROR_FILE_ENCRYPT;
        }
        Upg_File::deleteAllFileInPath(pkgDst.c_str());
        size_t fnPos = pkgScr.rfind('/');
        if(fnPos == string::npos) {
            cgi_debug("PKG INVALID : %s", pkgScr.c_str());
            return BW_ERROR_OPENSSL_PKG;
        }
        pkgDst += pkgScr.substr(fnPos+1);
        cgi_debug("pkgDst openssl : %s", pkgDst.c_str());
        if(FCGI_file_exist(pkgDst.c_str()))
        {
            char cmd[CMD_LEN] = {0};
            snprintf(cmd, CMD_LEN, "rm %s -f", pkgDst.c_str());
            cgi_debug("rm_cmd = %s", cmd);
            system(cmd);
            sync();
        }
        Upg_File::bw_comm_Encrypt(pkgScr.c_str(), pkgDst.c_str(), passWord.c_str());

        if(!FCGI_file_exist(pkgDst.c_str()) || FCGI_file_size(pkgDst.c_str()) == 0)
        {
            cgi_debug("ENCRYPT FILE ERROR");
            return BW_ERROR_FILE_ENCRYPT;
        }

        pFcgiReq->enableDown();
        pFcgiReq->setDownloadfile(pkgDst.c_str());
        return BWENC_ERROR_NONE;
    }

    const char *Enc_Upgrade::getSigMd5Value(FcgiRequest *pFcgiReq)
    {
        string fileName;
        if(pFcgiReq->getUploadfile())
            fileName = pFcgiReq->getUploadfile();
        if(fileName.empty() || pFcgiReq->getUploadfileLen() == 0
            || fileName.find('/') == string::npos)
        {
            cgi_debug("PKG INVALID");
            return bwenc_common_ack(BW_ERROR_FILE_ABNORMAL);
        }
        string md5Value = Upg_File::getMd5Value(fileName);
        if(md5Value.empty())
            return bwenc_common_ack(BW_ERROR_GET_FILEMD5);
#if 0   /*  取消获取版本号功能   */
        string versionStr;
        if(Upg_File::File_isExcecutable(fileName.c_str()))
        {
            char cmd[CMD_LEN] = {0};
            char result[CMD_LEN] = {0};
            snprintf(cmd, CMD_LEN, "%s -version", fileName.c_str());
            Upg_File::File_Shell_exec(cmd, result, CMD_LEN);
            versionStr = result;
        }
        else
            versionStr = "";

        /*  判断版本号   */
        if(versionStr.size() > 20)
        {
            cgi_debug("VERSION ERROR : %s", versionStr.c_str());
            return bwenc_common_ack(BW_ERROR_VERSION_INVALID);
        }
        if(!versionStr.empty())
        {
            vector<string>Array;
            BWStr::split_ex(Array, ".", versionStr);
            if(Array.size() != 3 || Array[0].find('v') == string::npos)
            {
                cgi_debug("VERSION ERROR : %s", versionStr.c_str());
                return bwenc_common_ack(BW_ERROR_VERSION_INVALID);
            }
        }
#endif
        rapidjson::Document m_doc;
        m_doc.Parse(bwenc_common_ack(BWENC_ERROR_NONE));
        if(m_doc.HasParseError() || !m_doc.IsObject())
        {
            cgi_debug("BUILD JSON ERROR");
            return bwenc_common_ack(BW_ERROR_GET_FILEMD5);
        }
        rapidjson::Document::AllocatorType & allocator = m_doc.GetAllocator();
        rapidjson::Value retData(rapidjson::kObjectType);
        retData.AddMember(MD5_KEY, rapidjson::StringRef(md5Value.c_str()), allocator);
        m_doc.AddMember(RETDATA_KEY, retData, allocator);

        rapidjson::StringBuffer sb;
        rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
        m_doc.Accept(writer);

        respStr.clear();
        respStr = sb.GetString();
        return respStr.c_str();
    }

    eENC_ERROR Enc_Upgrade::stopUpgProcess()
    {
        bool ret;
        ret = Upg_File::progressIsRun(jsoncfg.upgradeServer.c_str());
        if(!ret)
        {
            cgi_debug("%s ALREADY STOP", jsoncfg.upgradeServer.c_str());
            return BWENC_ERROR_NONE;
        }
        MsgList * pMsg = new MsgList(jsoncfg.msgPath.c_str(), jsoncfg.projectId);
        BWMsg msg;
        size_t msgLen = sizeof(msg.content);
        string msgStr;
        int count = 3;
        while(true)
        {
            msg.type = jsoncfg.msgType;
            memset(msg.content, 0, msgLen);
            msgStr.clear();

            U32 msgNum = pMsg->getMsgNum();
            int semNum = pMsg->getSemVal();
            if((int)msgNum > semNum)
                pMsg->setSemVal((short)msgNum);

            pMsg->getMsg(&msg, msgLen);
            msgStr = msg.content;
            if(UPGRADE_FINISH_FALG == msgStr)
            {
                cgi_debug("%s finish, begin stop process", jsoncfg.upgradeServer.c_str());
                break;
            }

            if(msgStr.empty())
                count--;
            if(count <= 0)
                break;
        }
        pMsg->deleteMsgList();
        SAFE_DELETE_PTR(pMsg);

        return Upg_File::stopProgress(jsoncfg.upgradeServer.c_str()) ? BWENC_ERROR_NONE : BW_ERROR_UPGSTOP_ERROR;
    }

    const char *Enc_Upgrade::getVersions()
    {
        rapidjson::Document m_doc;
        m_doc.Parse(bwenc_common_ack(BWENC_ERROR_NONE));
        if(m_doc.HasParseError() || !m_doc.IsObject())
        {
            cgi_debug("build reply json error");
            return bwenc_common_ack(BW_ERROR_GET_VERSION);
        }
        rapidjson::Document::AllocatorType & allocator = m_doc.GetAllocator();
//        auto & allocator = m_doc.GetAllocator();
        FILE_INFO localFiles = getLocalFileInfo();

        rapidjson::Value fileInfo(rapidjson::kArrayType);
        for(const auto & i : localFiles.execFileInfo)
        {
            rapidjson::Value sigFile(rapidjson::kObjectType);
            sigFile.AddMember(FILENAME_KEY, rapidjson::StringRef(i.fileName.c_str()), allocator);
            sigFile.AddMember(VERSION_KEY, rapidjson::StringRef(i.version.c_str()), allocator);
            fileInfo.PushBack(sigFile, allocator);
        }
        for(const auto & i : localFiles.normFileInfo)
        {
            rapidjson::Value sigFile(rapidjson::kObjectType);
            sigFile.AddMember(FILENAME_KEY, rapidjson::StringRef(i.fileName.c_str()), allocator);
            sigFile.AddMember(VERSION_KEY, rapidjson::StringRef(i.version.c_str()), allocator);
            fileInfo.PushBack(sigFile, allocator);
        }
        if((int)fileInfo.Size() != localFiles.normNum + localFiles.execNum)
        {
            cgi_debug("file numbers error");
            return bwenc_common_ack(BW_ERROR_GET_VERSION);
        }
        m_doc.AddMember(FILEINFO_KEY, fileInfo, allocator);

        rapidjson::StringBuffer sb;
        rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
        m_doc.Accept(writer);

        respStr.clear();
        respStr = sb.GetString();
        return respStr.c_str();
    }

    const char *Enc_Upgrade::buildProcessJson(string key)
    {
        if(proMsg.find(key) == proMsg.end()) {
            cgi_debug("UNKNOWN KEY : %s", key.c_str());
            return bwenc_common_ack(BWENC_ERROR_UNKNOW);
        }

        rapidjson::Document m_doc;
        m_doc.SetObject();
        rapidjson::Document::AllocatorType & allocator = m_doc.GetAllocator();
        m_doc.AddMember(RETCOD_KEY, rapidjson::StringRef(key.c_str()) ,allocator);
        m_doc.AddMember(RETMSG_KEY, rapidjson::StringRef(proMsg.find(key)->second.retMsg.c_str()) ,allocator);
        rapidjson::Value retData(rapidjson::kObjectType);
        retData.AddMember(SCHEDULE_KEY, rapidjson::StringRef(proMsg.find(key)->second.schedule.c_str()) ,allocator);
        m_doc.AddMember(RETDATA_KEY, retData, allocator);

        rapidjson::StringBuffer sb;
        rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
        m_doc.Accept(writer);

        respStr.clear();
        respStr = sb.GetString();
        return respStr.c_str();
    }

}	/*	namespace	*/
